package com.uzai.console.service.report.impl;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.converters.longconverter.LongStringConverter;
import com.alibaba.excel.util.StringUtils;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.uzai.common.enums.DeviceTypeEnum;
import com.uzai.common.enums.TakeBalStatusEnum;
import com.uzai.common.exception.BusinessException;
import com.uzai.common.result.ResponseCode;
import com.uzai.common.utils.CommonUtil;
import com.uzai.common.utils.Math;
import com.uzai.console.common.ResponseMsg;
import com.uzai.console.common.UzaiRespVo;
import com.uzai.console.common.utils.DateUtil;
import com.uzai.console.common.utils.Tools;
import com.uzai.console.common.utils.ZipUtils;
import com.uzai.console.config.UzaiConsoleSysConfig;
import com.uzai.console.constant.CacheKey;
import com.uzai.console.constant.Const;
import com.uzai.console.dto.feign.report.ExpenseCountReportFeignDto;
import com.uzai.console.dto.report.ExpenseCountIndicatorDto;
import com.uzai.console.dto.report.ExpenseCountReportQuery;
import com.uzai.console.dto.report.ExpenseCountReportExportResultDto;
import com.uzai.console.dto.report.ExpenseCountReportQuery;
import com.uzai.console.dto.takebal.usertakebal.UserTakeBalQuery;
import com.uzai.console.dto.wechatprivate.devicewechatinfo.DeviceWechatInfoQuery;
import com.uzai.console.dto.wechatwork.devicewxworkinfo.DeviceWxworkInfoQuery;
import com.uzai.console.dto.wxpubmanage.WxpubInfoListQuery;
import com.uzai.console.entity.DeviceWechatInfo;
import com.uzai.console.entity.DeviceWxworkInfo;
import com.uzai.console.entity.Merchant;
import com.uzai.console.entity.wxpubmanage.WxpubInfoEntity;
import com.uzai.console.enums.ExportInfoTypeEnum;
import com.uzai.console.enums.SmsType;
import com.uzai.console.mapper.*;
import com.uzai.console.mapper.stats.OrderProfitStatsMapper;
import com.uzai.console.service.device.DeviceService;
import com.uzai.console.service.exportinfo.ExportInfoService;
import com.uzai.console.service.feign.UzaiReportServerFeignService;
import com.uzai.console.service.report.ExpenseCountReportService;
import com.uzai.console.vo.exportinfo.ExportAmountVo;
import com.uzai.console.vo.feign.report.ExpenseCountIndicatorReportFeignVo;
import com.uzai.console.vo.feign.report.ExpenseCountReportFeignVo;
import com.uzai.console.vo.report.ExpenseCountIndicatorReportVo;
import com.uzai.console.vo.report.ExpenseCountReportVo;
import com.uzai.console.vo.report.ExpenseCountReportExport;
import com.uzai.console.vo.report.ExpenseCountReportVo;
import com.uzai.console.vo.takebal.usertakebal.UserTakeBalReportVo;
import org.apache.tools.zip.ZipOutputStream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * 支出统计报表
 * @author liuqi
 * @date 2021年08月25日 20:18
 */
@Service
public class ExpenseCountReportServiceImpl implements ExpenseCountReportService {

    private Logger logger = LoggerFactory.getLogger(ExpenseCountReportServiceImpl.class);

    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private OrderProfitStatsMapper orderProfitStatsMapper;
    @Autowired
    private DeviceWechatInfoMapper deviceWechatInfoMapper;
    @Autowired
    private DeviceWxworkInfoMapper deviceWxworkInfoMapper;
    @Autowired
    private WxpubInfoMapper wxpubInfoMapper;
    @Autowired
    private UzaiReportServerFeignService uzaiReportServerFeignService;
    @Autowired
    private DeviceService deviceService;
    @Autowired
    private UserTakeBalMapper userTakeBalMapper;
    @Autowired
    private SysConfigMapper sysConfigMapper;
    @Autowired
    private MerchantMapper merchantMapper;
    @Autowired
    private UzaiConsoleSysConfig uzaiConsoleSysConfig;
    @Autowired
    private ExportInfoService exportInfoService;

    /**
     * 支出统计报表
     * @author liuqi
     * @date 2021/8/25 11:38
     * @param expenseCountReportQuery
     * @return null
     */
    public Page<ExpenseCountReportVo> expenseCountReport(ExpenseCountReportQuery expenseCountReportQuery){

        //返回到页面分页对象
        Page<ExpenseCountReportVo> pageVo = new Page<>();
        expenseCountReportQuery.convert(pageVo);
        //新建返回到页面的LIST对象
        List<ExpenseCountReportVo> expenseCountReportVoList = new ArrayList<>();

        Long merId = expenseCountReportQuery.getMerId();
        String deviceType = expenseCountReportQuery.getDeviceType();
        //机器人查询条件
        List<Long> deviceUniqueIdList = expenseCountReportQuery.getDeviceUniqueIdList();
        //查询开始时间
        Integer queryStartTime = expenseCountReportQuery.getQueryStartTime();
        //查询结束时间
        Integer queryEndTime = expenseCountReportQuery.getQueryEndTime();

        //判断查询条件
        if(merId == null){
            throw new BusinessException(ResponseCode.BUSINESS_EXCEPTION, "系统参数错误");
        }

        if(StringUtils.isBlank(deviceType)){
            throw new BusinessException(ResponseCode.BUSINESS_EXCEPTION, "请选择设备类型");
        }

        if(queryStartTime == null){
            throw new BusinessException(ResponseCode.BUSINESS_EXCEPTION, "请输入时间范围");
        }

        if(queryEndTime == null){
            throw new BusinessException(ResponseCode.BUSINESS_EXCEPTION, "请输入时间范围");
        }

        int now = DateUtil.getNowTime();

        if(queryEndTime.intValue() < queryStartTime.intValue()){
            throw new BusinessException(ResponseCode.BUSINESS_EXCEPTION, "结束时间不能早于开始时间");
        }

        if(queryEndTime.intValue()- queryStartTime.intValue() > 31*24*3600){
            throw new BusinessException(ResponseCode.BUSINESS_EXCEPTION, "最多只能查询31天的报表");
        }

        if(now - queryStartTime.intValue() > 90*24*3600){
            throw new BusinessException(ResponseCode.BUSINESS_EXCEPTION, "最早只能查询90天以内的报表");
        }

        //手动处理机器人分页查询-如果是机器人昵称，则按照中文gbk排序
        List<OrderItem> orderItemList = expenseCountReportQuery.getOrderItemList();
        if(orderItemList != null && orderItemList.size() > 0){
            for (OrderItem orderItem :orderItemList){
                if("device_name".equals(orderItem.getColumn())){
                    orderItem.setColumn(" convert( " + orderItem.getColumn() + " using gbk) ");
                }
            }
        }

        //个人微信
        if(DeviceTypeEnum.DT_PC_WECHAT.getKey().equals(deviceType)){
            Page<DeviceWechatInfo> page = new Page<>();
            expenseCountReportQuery.convert(page);
            DeviceWechatInfoQuery deviceWechatInfoQuery = new DeviceWechatInfoQuery();
            BeanUtils.copyProperties(expenseCountReportQuery, deviceWechatInfoQuery);
            deviceWechatInfoQuery.setIdList(expenseCountReportQuery.getDeviceUniqueIdList());
            deviceWechatInfoQuery.setMerId(merId);
            ArrayList<DeviceWechatInfo> deviceWechatInfoList =  deviceWechatInfoMapper.findByList(page, deviceWechatInfoQuery);
            BeanUtils.copyProperties(page, pageVo);
            if(deviceWechatInfoList != null && deviceWechatInfoList.size() > 0){
                for (DeviceWechatInfo deviceWechatInfo : deviceWechatInfoList){


                    ExpenseCountReportVo expenseCountReportVo = new ExpenseCountReportVo();
                    expenseCountReportVo.setDeviceUniqueId(deviceWechatInfo.getId());
                    expenseCountReportVo.setDeviceName(deviceWechatInfo.getDeviceName());
                    expenseCountReportVo.setDeviceRemark(deviceWechatInfo.getDeviceRemark());
                    expenseCountReportVo.setHeadImgUrl(deviceWechatInfo.getHeadImgUrl());
                    expenseCountReportVoList.add(expenseCountReportVo);
                }
            }
        }else if(DeviceTypeEnum.DT_WORK_WECHAT.getKey().equals(deviceType)){
            Page<DeviceWxworkInfo> page = new Page<>();
            expenseCountReportQuery.convert(page);
            DeviceWxworkInfoQuery deviceWxworkInfoQuery = new DeviceWxworkInfoQuery();
            BeanUtils.copyProperties(expenseCountReportQuery, deviceWxworkInfoQuery);
            deviceWxworkInfoQuery.setIdList(expenseCountReportQuery.getDeviceUniqueIdList());
            deviceWxworkInfoQuery.setMerId(merId);
            ArrayList<DeviceWxworkInfo> deviceWxworkInfoList =  deviceWxworkInfoMapper.findByList(page, deviceWxworkInfoQuery);
            BeanUtils.copyProperties(page, pageVo);
            if(deviceWxworkInfoList != null && deviceWxworkInfoList.size() > 0){
                for (DeviceWxworkInfo deviceWxworkInfo : deviceWxworkInfoList){
                    ExpenseCountReportVo expenseCountReportVo = new ExpenseCountReportVo();
                    expenseCountReportVo.setDeviceUniqueId(deviceWxworkInfo.getId());
                    expenseCountReportVo.setDeviceName(deviceWxworkInfo.getDeviceName());
                    expenseCountReportVo.setDeviceRemark(deviceWxworkInfo.getDeviceRemark());
                    expenseCountReportVo.setHeadImgUrl(deviceWxworkInfo.getHeadImgUrl());
                    expenseCountReportVoList.add(expenseCountReportVo);
                }
            }
        }else if(DeviceTypeEnum.WX_PUB.getKey().equals(deviceType)){
            Page<WxpubInfoEntity> page = new Page<>();
            expenseCountReportQuery.convert(page);
            WxpubInfoListQuery wxpubInfoListQuery = new WxpubInfoListQuery();
            BeanUtils.copyProperties(expenseCountReportQuery, wxpubInfoListQuery);
            wxpubInfoListQuery.setIdList(expenseCountReportQuery.getDeviceUniqueIdList());
            wxpubInfoListQuery.setMerId(merId);
            List<WxpubInfoEntity> wxpubInfoEntityList =  wxpubInfoMapper.queryList(page, wxpubInfoListQuery);
            BeanUtils.copyProperties(page, pageVo);
            if(wxpubInfoEntityList != null && wxpubInfoEntityList.size() > 0){
                for (WxpubInfoEntity wxpubInfoEntity : wxpubInfoEntityList){
                    ExpenseCountReportVo expenseCountReportVo = new ExpenseCountReportVo();
                    expenseCountReportVo.setDeviceUniqueId(wxpubInfoEntity.getId());
                    expenseCountReportVo.setDeviceName(wxpubInfoEntity.getDeviceName());
                    expenseCountReportVo.setDeviceRemark(wxpubInfoEntity.getDeviceRemark());
                    expenseCountReportVo.setHeadImgUrl(wxpubInfoEntity.getHeadImgUrl());
                    expenseCountReportVoList.add(expenseCountReportVo);
                }
            }
        }

        //有机器人才去查询
        if(expenseCountReportVoList != null && expenseCountReportVoList.size() > 0){
            //封装微服务机器人参数
            List<Long> robotIds = new ArrayList<>();
            for(ExpenseCountReportVo expenseCountReportVo : expenseCountReportVoList){
                //子账号负责的机器人列表
                List<Long> subDeviceUniqueIdList = expenseCountReportQuery.getSubDeviceUniqueIdList();
                if(subDeviceUniqueIdList != null && subDeviceUniqueIdList.size() > 0){
                    for (Long subDeviceUniqueId : subDeviceUniqueIdList){
                        if(subDeviceUniqueId.longValue() == expenseCountReportVo.getDeviceUniqueId().longValue()){
                            robotIds.add(expenseCountReportVo.getDeviceUniqueId());
                        }
                    }
                }else{
                    robotIds.add(expenseCountReportVo.getDeviceUniqueId());
                }
            }

            ExpenseCountReportFeignDto expenseCountReportFeignDto = new ExpenseCountReportFeignDto();
            expenseCountReportFeignDto.setStartTime(queryStartTime);
            expenseCountReportFeignDto.setEndTime(queryEndTime);
            expenseCountReportFeignDto.setRobotIds(robotIds);
            expenseCountReportFeignDto.setMerId(merId);
            expenseCountReportFeignDto.setDeviceType(DeviceTypeEnum.getByKey(deviceType).getId());
            UzaiRespVo<List<ExpenseCountReportFeignVo>> uzaiRespVo =  uzaiReportServerFeignService.expenseCountSearch(expenseCountReportFeignDto);
            //logger.info("----调用支出统计报表微服务---para={}, result={}", JSONObject.toJSONString(expenseCountReportFeignDto), JSONObject.toJSONString(uzaiRespVo));
            if(uzaiRespVo != null && uzaiRespVo.getCode() == 200){
                List<ExpenseCountReportFeignVo> expenseCountReportFeignVoList = uzaiRespVo.getData();
                if(expenseCountReportFeignVoList != null && expenseCountReportFeignVoList.size() > 0){
                    for (ExpenseCountReportFeignVo expenseCountReportFeignVo : expenseCountReportFeignVoList){
                        for (ExpenseCountReportVo expenseCountReportVo : expenseCountReportVoList){
                            //匹配查找返回列表中的对象
                            if(expenseCountReportVo.getDeviceUniqueId().longValue() == expenseCountReportFeignVo.getRobotId().longValue()){
                                //对象赋值
                                BeanUtils.copyProperties(expenseCountReportFeignVo, expenseCountReportVo);
                                break;
                            }
                        }
                    }
                }
            }

            //循环赋值提现金额信息
            for (ExpenseCountReportVo expenseCountReportVo : expenseCountReportVoList){
                //自动提现总金额
                Double withdrawalTotalBalance_auto = 0.0D;
                UserTakeBalQuery userTakeBalQuery_success_auto = new UserTakeBalQuery();
                userTakeBalQuery_success_auto.setMerId(merId);
                userTakeBalQuery_success_auto.setDeviceUniqueId(expenseCountReportVo.getDeviceUniqueId());
                userTakeBalQuery_success_auto.setQueryStartTime(queryStartTime);
                userTakeBalQuery_success_auto.setQueryEndTime(queryEndTime);
                //自动提现成功和手动审核成功
                userTakeBalQuery_success_auto.setStatusList(Arrays.asList(TakeBalStatusEnum.TBS_AUTO_TAKEBAL_SUCCESS.getValue()));
                UserTakeBalReportVo userTakeBalReportVo_success_auto = userTakeBalMapper.selectUserTakeBalReport(userTakeBalQuery_success_auto);
                if(userTakeBalReportVo_success_auto != null){
                    //自动提现总金额
                    withdrawalTotalBalance_auto = Tools.getDouble(userTakeBalReportVo_success_auto.getTakeBalTotal());
                    expenseCountReportVo.setWithdrawalAutoTotalBalance(withdrawalTotalBalance_auto);
                }

                //手动审核成功
                Double withdrawalTotalBalance_hander = 0.0D;
                UserTakeBalQuery userTakeBalQuery_success_hander = new UserTakeBalQuery();
                userTakeBalQuery_success_hander.setMerId(merId);
                userTakeBalQuery_success_hander.setDeviceUniqueId(expenseCountReportVo.getDeviceUniqueId());
                userTakeBalQuery_success_hander.setQueryStartTime(queryStartTime);
                userTakeBalQuery_success_hander.setQueryEndTime(queryEndTime);
                //手动审核成功
                userTakeBalQuery_success_hander.setStatusList(Arrays.asList(TakeBalStatusEnum.TBS_MANUAL_AUDIT_SUCCESS.getValue()));
                UserTakeBalReportVo userTakeBalReportVo_success_hander = userTakeBalMapper.selectUserTakeBalReport(userTakeBalQuery_success_hander);
                if(userTakeBalReportVo_success_hander != null){
                    //手动审核成功
                    withdrawalTotalBalance_hander = Tools.getDouble(userTakeBalReportVo_success_hander.getTakeBalTotal());
                    expenseCountReportVo.setWithdrawalHanderTotalBalance(withdrawalTotalBalance_hander);
                }

                //提现总金额=手动审核成功+自动提现总金额
                Double withdrawalTotalBalance = Math.add(withdrawalTotalBalance_auto, withdrawalTotalBalance_hander);
                expenseCountReportVo.setWithdrawalTotalBalance(withdrawalTotalBalance);
                //总提现奖励
                Double totalRewards = Tools.getDouble(expenseCountReportVo.getTotalRewards());
                //总支出=提现总金额+总提现奖励
                Double totalExpenditure = Math.add(withdrawalTotalBalance, totalRewards);
                expenseCountReportVo.setTotalExpenditure(totalExpenditure);

                //总支出红包 = 提现总金额 + 总奖励红包
                //总奖励红包
                Double totalRedPacket = Tools.getDouble(expenseCountReportVo.getTotalRedPacket());
                Double totalExpenditureRedPacket = Math.add(withdrawalTotalBalance, totalRedPacket);
                expenseCountReportVo.setTotalExpenditureRedPacket(totalExpenditureRedPacket);

                //总支出余额 = 总奖励余额
                //总奖励余额
                Double totalBalance = expenseCountReportVo.getTotalBalance();
                expenseCountReportVo.setTotalExpenditureBalance(totalBalance);
            }
        }

        pageVo.setRecords(expenseCountReportVoList);
        //将分页信息复制到返回到页面的分页MO当中
        return pageVo;
    }


    /**
     * 支出统计指标查询
     * @author liuqi
     * @date 2021/8/25 11:38
     * @param expenseCountIndicatorDto
     * @return null
     */
    public ExpenseCountIndicatorReportVo expenseCountIndicator(ExpenseCountIndicatorDto expenseCountIndicatorDto){

        //返回到页面结果
        ExpenseCountIndicatorReportVo expenseCountIndicatorReportVo = new ExpenseCountIndicatorReportVo();

        Long merId = expenseCountIndicatorDto.getMerId();
        String deviceType = expenseCountIndicatorDto.getDeviceType();
        //机器人查询条件
        List<Long> deviceUniqueIdList = expenseCountIndicatorDto.getDeviceUniqueIdList();
        //查询开始时间
        Integer queryStartTime = expenseCountIndicatorDto.getQueryStartTime();
        //查询结束时间
        Integer queryEndTime = expenseCountIndicatorDto.getQueryEndTime();

        //判断查询条件
        if(merId == null){
            throw new BusinessException(ResponseCode.BUSINESS_EXCEPTION, "系统参数错误");
        }

        if(StringUtils.isBlank(deviceType)){
            throw new BusinessException(ResponseCode.BUSINESS_EXCEPTION, "请选择设备类型");
        }

        if(queryStartTime == null){
            throw new BusinessException(ResponseCode.BUSINESS_EXCEPTION, "请输入时间范围");
        }

        if(queryEndTime == null){
            throw new BusinessException(ResponseCode.BUSINESS_EXCEPTION, "请输入时间范围");
        }

        int now = DateUtil.getNowTime();

        if(queryEndTime.intValue() < queryStartTime.intValue()){
            throw new BusinessException(ResponseCode.BUSINESS_EXCEPTION, "结束时间不能早于开始时间");
        }

        if(queryEndTime.intValue()- queryStartTime.intValue() > 31*24*3600){
            throw new BusinessException(ResponseCode.BUSINESS_EXCEPTION, "最多只能查询31天的报表");
        }

        if(now - queryStartTime.intValue() > 90*24*3600){
            throw new BusinessException(ResponseCode.BUSINESS_EXCEPTION, "最早只能查询90天以内的报表");
        }

        //新建返回到页面的LIST对象
        //封装微服务机器人参数
        List<Long> robotIds = new ArrayList<>();

        //个人微信
        if(DeviceTypeEnum.DT_PC_WECHAT.getKey().equals(deviceType)){
            DeviceWechatInfoQuery deviceWechatInfoQuery = new DeviceWechatInfoQuery();
            BeanUtils.copyProperties(expenseCountIndicatorDto, deviceWechatInfoQuery);
            deviceWechatInfoQuery.setIdList(deviceUniqueIdList);
            deviceWechatInfoQuery.setMerId(merId);
            ArrayList<DeviceWechatInfo> deviceWechatInfoList =  deviceWechatInfoMapper.findByList(deviceWechatInfoQuery);
            if(deviceWechatInfoList != null && deviceWechatInfoList.size() > 0){
                for (DeviceWechatInfo deviceWechatInfo : deviceWechatInfoList){
                    robotIds.add(deviceWechatInfo.getId());
                }
            }
        }else if(DeviceTypeEnum.DT_WORK_WECHAT.getKey().equals(deviceType)){
            Page<DeviceWxworkInfo> page = new Page<>();
            DeviceWxworkInfoQuery deviceWxworkInfoQuery = new DeviceWxworkInfoQuery();
            BeanUtils.copyProperties(expenseCountIndicatorDto, deviceWxworkInfoQuery);
            deviceWxworkInfoQuery.setIdList(deviceUniqueIdList);
            deviceWxworkInfoQuery.setMerId(merId);
            ArrayList<DeviceWxworkInfo> deviceWxworkInfoList =  deviceWxworkInfoMapper.findByList(deviceWxworkInfoQuery);
            if(deviceWxworkInfoList != null && deviceWxworkInfoList.size() > 0){
                for (DeviceWxworkInfo deviceWxworkInfo : deviceWxworkInfoList){
                    robotIds.add(deviceWxworkInfo.getId());
                }
            }
        }else if(DeviceTypeEnum.WX_PUB.getKey().equals(deviceType)){
            WxpubInfoListQuery wxpubInfoListQuery = new WxpubInfoListQuery();
            BeanUtils.copyProperties(expenseCountIndicatorDto, wxpubInfoListQuery);
            wxpubInfoListQuery.setIdList(deviceUniqueIdList);
            wxpubInfoListQuery.setMerId(merId);
            List<WxpubInfoEntity> wxpubInfoEntityList =  wxpubInfoMapper.queryList(wxpubInfoListQuery);
            if(wxpubInfoEntityList != null && wxpubInfoEntityList.size() > 0){
                for (WxpubInfoEntity wxpubInfoEntity : wxpubInfoEntityList){
                    robotIds.add(wxpubInfoEntity.getId());
                }
            }
        }

        //有机器人才去查询
        if(robotIds != null && robotIds.size() > 0){
            //封装微服务机器人参数
            List<Long> robotIds_new = new ArrayList<>();
            for(Long deviceUniqueId : robotIds){
                //子账号负责的机器人列表
                List<Long> subDeviceUniqueIdList = expenseCountIndicatorDto.getSubDeviceUniqueIdList();
                if(subDeviceUniqueIdList != null && subDeviceUniqueIdList.size() > 0){
                    for (Long subDeviceUniqueId : subDeviceUniqueIdList){
                        if(subDeviceUniqueId.longValue() == deviceUniqueId.longValue()){
                            robotIds_new.add(deviceUniqueId);
                        }
                    }
                }else{
                    robotIds_new.add(deviceUniqueId);
                }
            }

            ExpenseCountReportFeignDto expenseCountReportFeignDto = new ExpenseCountReportFeignDto();
            expenseCountReportFeignDto.setStartTime(queryStartTime);
            expenseCountReportFeignDto.setEndTime(queryEndTime);
            expenseCountReportFeignDto.setRobotIds(robotIds_new);
            expenseCountReportFeignDto.setMerId(merId);
            expenseCountReportFeignDto.setDeviceType(DeviceTypeEnum.getByKey(deviceType).getId());
            UzaiRespVo<ExpenseCountIndicatorReportFeignVo> uzaiRespVo =  uzaiReportServerFeignService.expenseCountIndicatorSerach(expenseCountReportFeignDto);
            //logger.info("----调用支出统计报表微服务---para={}, result={}", JSONObject.toJSONString(expenseCountReportFeignDto), JSONObject.toJSONString(uzaiRespVo));
            if(uzaiRespVo != null && uzaiRespVo.getCode() == 200){
                ExpenseCountIndicatorReportFeignVo expenseCountIndicatorReportFeignVo = uzaiRespVo.getData();
                if(expenseCountIndicatorReportFeignVo != null){
                    //对象赋值
                    BeanUtils.copyProperties(expenseCountIndicatorReportFeignVo, expenseCountIndicatorReportVo);
                }
            }

            //自动提现总金额
            Double withdrawalTotalBalance_auto = 0.0D;
            UserTakeBalQuery userTakeBalQuery_success_auto = new UserTakeBalQuery();
            userTakeBalQuery_success_auto.setMerId(merId);
            userTakeBalQuery_success_auto.setDeviceUniqueIdList(robotIds);
            userTakeBalQuery_success_auto.setQueryStartTime(queryStartTime);
            userTakeBalQuery_success_auto.setQueryEndTime(queryEndTime);
            //自动提现成功和手动审核成功
            userTakeBalQuery_success_auto.setStatusList(Arrays.asList(TakeBalStatusEnum.TBS_AUTO_TAKEBAL_SUCCESS.getValue()));
            UserTakeBalReportVo userTakeBalReportVo_success_auto = userTakeBalMapper.selectUserTakeBalReport(userTakeBalQuery_success_auto);
            if(userTakeBalReportVo_success_auto != null){
                //自动提现总金额
                withdrawalTotalBalance_auto = Tools.getDouble(userTakeBalReportVo_success_auto.getTakeBalTotal());
                expenseCountIndicatorReportVo.setWithdrawalAutoTotalBalance(withdrawalTotalBalance_auto);
            }

            //人工提现总金额
            Double withdrawalTotalBalance_hander = 0.0D;
            UserTakeBalQuery userTakeBalQuery_success_hander = new UserTakeBalQuery();
            userTakeBalQuery_success_hander.setMerId(merId);
            userTakeBalQuery_success_hander.setDeviceUniqueIdList(robotIds);
            userTakeBalQuery_success_hander.setQueryStartTime(queryStartTime);
            userTakeBalQuery_success_hander.setQueryEndTime(queryEndTime);
            //自动提现成功和手动审核成功
            userTakeBalQuery_success_hander.setStatusList(Arrays.asList(TakeBalStatusEnum.TBS_MANUAL_AUDIT_SUCCESS.getValue()));
            UserTakeBalReportVo userTakeBalReportVo_success_hander = userTakeBalMapper.selectUserTakeBalReport(userTakeBalQuery_success_hander);
            if(userTakeBalReportVo_success_hander != null){
                //人工提现总金额
                withdrawalTotalBalance_hander = Tools.getDouble(userTakeBalReportVo_success_hander.getTakeBalTotal());
                expenseCountIndicatorReportVo.setWithdrawalHanderTotalBalance(withdrawalTotalBalance_hander);
            }

            //提现总金额=人工提现总金额+自动提现总金额
            Double withdrawalTotalBalance = Math.add(withdrawalTotalBalance_auto, withdrawalTotalBalance_hander);
            expenseCountIndicatorReportVo.setWithdrawalTotalBalance(withdrawalTotalBalance);
            //总奖励
            Double totalRewards = Tools.getDouble(expenseCountIndicatorReportVo.getTotalRewards());
            //总支出=提现总金额+总奖励
            Double totalExpenditure = Math.add(withdrawalTotalBalance, totalRewards);
            expenseCountIndicatorReportVo.setTotalExpenditure(totalExpenditure);
            //总支出红包 = 提现总金额 + 总奖励红包
            //总奖励红包
            Double totalRedPacket = Tools.getDouble(expenseCountIndicatorReportVo.getTotalRedPacket());
            Double totalExpenditureRedPacket = Math.add(withdrawalTotalBalance, totalRedPacket);
            expenseCountIndicatorReportVo.setTotalExpenditureRedPacket(totalExpenditureRedPacket);

            //总支出余额 = 总奖励余额
            //总奖励余额
            Double totalBalance = expenseCountIndicatorReportVo.getTotalBalance();
            expenseCountIndicatorReportVo.setTotalExpenditureBalance(totalBalance);
        }

        return expenseCountIndicatorReportVo;
    }

    /**
     * 支出统计查询结果导出文件前检验接口
     * @author liuqi
     * @date 2021/8/25 11:38
     * @param expenseCountReportQuery
     */
    public ExportAmountVo getExportAmount(ExpenseCountReportQuery expenseCountReportQuery){

        //执行分页查询对象
        //返回到页面分页对象
        Page<ExpenseCountReportVo> pageVo = new Page<>();
        expenseCountReportQuery.convert(pageVo);
        //新建返回到页面的LIST对象
        List<ExpenseCountReportVo> expenseCountReportVoList = new ArrayList<>();

        Long merId = expenseCountReportQuery.getMerId();
        String deviceType = expenseCountReportQuery.getDeviceType();
        //机器人查询条件
        List<Long> deviceUniqueIdList = expenseCountReportQuery.getDeviceUniqueIdList();
        //查询开始时间
        Integer queryStartTime = expenseCountReportQuery.getQueryStartTime();
        //查询结束时间
        Integer queryEndTime = expenseCountReportQuery.getQueryEndTime();

        //判断查询条件
        if(merId == null){
            throw new BusinessException(ResponseCode.BUSINESS_EXCEPTION, "系统参数错误");
        }

        if(StringUtils.isBlank(deviceType)){
            throw new BusinessException(ResponseCode.BUSINESS_EXCEPTION, "请选择设备类型");
        }

        if(queryStartTime == null){
            throw new BusinessException(ResponseCode.BUSINESS_EXCEPTION, "请输入时间范围");
        }

        if(queryEndTime == null){
            throw new BusinessException(ResponseCode.BUSINESS_EXCEPTION, "请输入时间范围");
        }

        int now = DateUtil.getNowTime();

        if(queryEndTime.intValue() < queryStartTime.intValue()){
            throw new BusinessException(ResponseCode.BUSINESS_EXCEPTION, "结束时间不能早于开始时间");
        }

        if(queryEndTime.intValue()- queryStartTime.intValue() > 31*24*3600){
            throw new BusinessException(ResponseCode.BUSINESS_EXCEPTION, "最多只能查询31天的报表");
        }

        if(now - queryStartTime.intValue() > 90*24*3600){
            throw new BusinessException(ResponseCode.BUSINESS_EXCEPTION, "最早只能查询90天以内的报表");
        }

        //手动处理机器人分页查询-如果是机器人昵称，则按照中文gbk排序
        List<OrderItem> orderItemList = expenseCountReportQuery.getOrderItemList();
        if(orderItemList != null && orderItemList.size() > 0){
            for (OrderItem orderItem :orderItemList){
                if("device_name".equals(orderItem.getColumn())){
                    orderItem.setColumn(" convert( " + orderItem.getColumn() + " using gbk) ");
                }
            }
        }

        //个人微信
        if(DeviceTypeEnum.DT_PC_WECHAT.getKey().equals(deviceType)){
            Page<DeviceWechatInfo> page = new Page<>();
            expenseCountReportQuery.convert(page);
            DeviceWechatInfoQuery deviceWechatInfoQuery = new DeviceWechatInfoQuery();
            BeanUtils.copyProperties(expenseCountReportQuery, deviceWechatInfoQuery);
            deviceWechatInfoQuery.setIdList(expenseCountReportQuery.getDeviceUniqueIdList());
            deviceWechatInfoQuery.setMerId(merId);
            ArrayList<DeviceWechatInfo> deviceWechatInfoList =  deviceWechatInfoMapper.findByList(page, deviceWechatInfoQuery);
            BeanUtils.copyProperties(page, pageVo);
            if(deviceWechatInfoList != null && deviceWechatInfoList.size() > 0){
                for (DeviceWechatInfo deviceWechatInfo : deviceWechatInfoList){


                    ExpenseCountReportVo expenseCountReportVo = new ExpenseCountReportVo();
                    expenseCountReportVo.setDeviceUniqueId(deviceWechatInfo.getId());
                    expenseCountReportVo.setDeviceName(deviceWechatInfo.getDeviceName());
                    expenseCountReportVo.setDeviceRemark(deviceWechatInfo.getDeviceRemark());
                    expenseCountReportVo.setHeadImgUrl(deviceWechatInfo.getHeadImgUrl());
                    expenseCountReportVoList.add(expenseCountReportVo);
                }
            }
        }else if(DeviceTypeEnum.DT_WORK_WECHAT.getKey().equals(deviceType)){
            Page<DeviceWxworkInfo> page = new Page<>();
            expenseCountReportQuery.convert(page);
            DeviceWxworkInfoQuery deviceWxworkInfoQuery = new DeviceWxworkInfoQuery();
            BeanUtils.copyProperties(expenseCountReportQuery, deviceWxworkInfoQuery);
            deviceWxworkInfoQuery.setIdList(expenseCountReportQuery.getDeviceUniqueIdList());
            deviceWxworkInfoQuery.setMerId(merId);
            ArrayList<DeviceWxworkInfo> deviceWxworkInfoList =  deviceWxworkInfoMapper.findByList(page, deviceWxworkInfoQuery);
            BeanUtils.copyProperties(page, pageVo);
            if(deviceWxworkInfoList != null && deviceWxworkInfoList.size() > 0){
                for (DeviceWxworkInfo deviceWxworkInfo : deviceWxworkInfoList){
                    ExpenseCountReportVo expenseCountReportVo = new ExpenseCountReportVo();
                    expenseCountReportVo.setDeviceUniqueId(deviceWxworkInfo.getId());
                    expenseCountReportVo.setDeviceName(deviceWxworkInfo.getDeviceName());
                    expenseCountReportVo.setDeviceRemark(deviceWxworkInfo.getDeviceRemark());
                    expenseCountReportVo.setHeadImgUrl(deviceWxworkInfo.getHeadImgUrl());
                    expenseCountReportVoList.add(expenseCountReportVo);
                }
            }
        }else if(DeviceTypeEnum.WX_PUB.getKey().equals(deviceType)){
            Page<WxpubInfoEntity> page = new Page<>();
            expenseCountReportQuery.convert(page);
            WxpubInfoListQuery wxpubInfoListQuery = new WxpubInfoListQuery();
            BeanUtils.copyProperties(expenseCountReportQuery, wxpubInfoListQuery);
            wxpubInfoListQuery.setIdList(expenseCountReportQuery.getDeviceUniqueIdList());
            wxpubInfoListQuery.setMerId(merId);
            List<WxpubInfoEntity> wxpubInfoEntityList =  wxpubInfoMapper.queryList(page, wxpubInfoListQuery);
            BeanUtils.copyProperties(page, pageVo);
            if(wxpubInfoEntityList != null && wxpubInfoEntityList.size() > 0){
                for (WxpubInfoEntity wxpubInfoEntity : wxpubInfoEntityList){
                    ExpenseCountReportVo expenseCountReportVo = new ExpenseCountReportVo();
                    expenseCountReportVo.setDeviceUniqueId(wxpubInfoEntity.getId());
                    expenseCountReportVo.setDeviceName(wxpubInfoEntity.getDeviceName());
                    expenseCountReportVo.setDeviceRemark(wxpubInfoEntity.getDeviceRemark());
                    expenseCountReportVo.setHeadImgUrl(wxpubInfoEntity.getHeadImgUrl());
                    expenseCountReportVoList.add(expenseCountReportVo);
                }
            }
        }


        //单个机器人查询总数
        long totalCount = pageVo.getTotal();
        if(totalCount == 0){
            throw new BusinessException(ResponseCode.BUSINESS_EXCEPTION, "查询结果记录数为0");
        }

        String price = sysConfigMapper.selectByKey("export_record_price");

        //计算本次导出费用
        double amountTotal = 0.00D;
        if(amountTotal <= 10000){ //少于1万条，只收取1元
            amountTotal = 1.00D;
        }else{//总导出数大于1万条，则根据单价来计算，超过1万条的按照100条的单价费用来计算
            amountTotal = com.uzai.common.utils.Math.add(1.0D, ((totalCount - 10000)/100 + 1) * Double.parseDouble(price));
        }
        ExportAmountVo  exportAmountVo = new ExportAmountVo();
        exportAmountVo.setAmountTotal(amountTotal);
        exportAmountVo.setCountTotal(totalCount);
        exportAmountVo.setPrice(Double.parseDouble(price));

        return exportAmountVo;
    }

    /**
     * 支出统计统计结果导出数据
     * @author liuqi
     * @date 2021/8/13 11:38
     * @param expenseCountReportExportResultDto
     * @return null
     */
    public void exportByQeuryResult(ExpenseCountReportExportResultDto expenseCountReportExportResultDto){

        if(expenseCountReportExportResultDto.getMerId() == null ){
            throw  new BusinessException(ResponseCode.BUSINESS_EXCEPTION, ResponseMsg.PARAM_ERROR);
        }

        if(org.apache.commons.lang3.StringUtils.isBlank(expenseCountReportExportResultDto.getCode())){
            throw  new BusinessException(ResponseCode.BUSINESS_EXCEPTION, "请输入验证码");
        }

        Merchant merchant = merchantMapper.selectById(expenseCountReportExportResultDto.getMerId());
        if(merchant == null ){
            throw new BusinessException(ResponseCode.BUSINESS_EXCEPTION, "运营商不存在");
        }

        //查询输入的验证码是否为系统默认密码
        if(!expenseCountReportExportResultDto.getCode().equals(uzaiConsoleSysConfig.getDefaultPassword())){

            String val = (String) redisTemplate.opsForValue().get(String.format(CacheKey.EXPENSE_COUNT_REPORT_EXPORT, expenseCountReportExportResultDto.getMerId()));
            if (org.apache.commons.lang3.StringUtils.isNotBlank(val)){
                throw new BusinessException(ResponseCode.BUSINESS_EXCEPTION, "30分钟只允许导出一次");
            }

            //获取存在redis中的验证码
            String codeByRedis = (String) redisTemplate.opsForValue().get(String.format(SmsType.SPECIAL_OPERATE.getDesc(), merchant.getMobile()));
            //判断验证码是否过期
            if (org.apache.commons.lang3.StringUtils.isBlank(codeByRedis)){
                throw new BusinessException(ResponseCode.BUSINESS_EXCEPTION, ResponseMsg.CODE_MISS);
            }

            //验证码是否正确
            if (!codeByRedis.equals(expenseCountReportExportResultDto.getCode())){
                throw new BusinessException(ResponseCode.BUSINESS_EXCEPTION, ResponseMsg.CODE_ERR);
            }

            //验证成功了删除验证码
            redisTemplate.delete(String.format(SmsType.SPECIAL_OPERATE.getDesc(), merchant.getMobile()));
        }


        //页面查询条件
        ExpenseCountReportQuery expenseCountReportQuery = expenseCountReportExportResultDto.getExpenseCountReportQuery();
        expenseCountReportQuery.setMerId(expenseCountReportExportResultDto.getMerId());

        //计算费用
        ExportAmountVo exportAmountVo = getExportAmount(expenseCountReportQuery);

        //生成ZIP文件流
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        ZipOutputStream out = new ZipOutputStream(outputStream);

        //每个excel表格订单最大数为10000条
        int exportExcelMaxNum = Const.ExprotFile.EXPORT_EXCEL_MAX_NUM;
        //导出excel文件序号
        int exportFileNumber = 0;

        //存放导出文件对象(一万条一个表格)
        List<ExpenseCountReportExport> expenseCountReportExportList = new ArrayList<>();
        //分页查询（每页10条）
        int page = 1;
        expenseCountReportQuery.setCurrent(page); //只查第一页
        expenseCountReportQuery.setSize(10); //每页查询10个
        Page<ExpenseCountReportVo> expenseCountReportVoPage = expenseCountReport(expenseCountReportQuery);
        while (expenseCountReportVoPage != null && expenseCountReportVoPage.getRecords() != null && expenseCountReportVoPage.getRecords().size() > 0) {
            for (ExpenseCountReportVo expenseCountReportVo : expenseCountReportVoPage.getRecords()) {
                ExpenseCountReportExport expenseCountReportExport = new ExpenseCountReportExport();
                BeanUtils.copyProperties(expenseCountReportVo, expenseCountReportExport);
                expenseCountReportExportList.add(expenseCountReportExport);

                //判断条数，如果条数大于10000条，生成excel文件
                if(expenseCountReportExportList.size() >= exportExcelMaxNum){
                    ByteArrayOutputStream byteArrayOutputStream = null;
                    try {
                        //导出的文件序号,每次导出+1
                        exportFileNumber ++ ;
                        String fileName = "支出统计报表_" + exportFileNumber +".xlsx";
                        //创建流
                        byteArrayOutputStream = new ByteArrayOutputStream();
                        //打包成ZIP文件
                        EasyExcel.write(byteArrayOutputStream, ExpenseCountReportExport.class).registerConverter(new LongStringConverter()).sheet("支出统计报表").doWrite(expenseCountReportExportList);
                        ZipUtils.zip(out, new ByteArrayInputStream(byteArrayOutputStream.toByteArray()), fileName);
                        byteArrayOutputStream.close();
                        //清空本次导出的数据列表
                        expenseCountReportExportList.clear();
                    }catch (Exception e){
                        if(byteArrayOutputStream != null){
                            try {
                                byteArrayOutputStream.close();
                            } catch (IOException ex) {
                                logger.error(ex.getMessage(), ex);
                            }
                        }
                        logger.error("----导出支出统计报表异常--error={}", e.getMessage());
                    }
                }

            }
            //循环查询下一页
            page ++;
            //最多支持导出100页数据
            if(page > 100){
                break;
            }
            expenseCountReportQuery.setCurrent(page);
            expenseCountReportVoPage = expenseCountReport(expenseCountReportQuery);
        }

        //最后将剩余不足10000条的记录，生成excel文件
        if(expenseCountReportExportList.size() > 0){
            ByteArrayOutputStream byteArrayOutputStream = null;
            try {
                //导出的文件序号,每次导出+1
                exportFileNumber ++ ;
                String fileName = "支出统计报表_" + exportFileNumber +".xlsx";
                //创建流
                byteArrayOutputStream = new ByteArrayOutputStream();
                //打包成ZIP文件
                EasyExcel.write(byteArrayOutputStream, ExpenseCountReportExport.class).registerConverter(new LongStringConverter()).sheet("支出统计报表").doWrite(expenseCountReportExportList);
                ZipUtils.zip(out, new ByteArrayInputStream(byteArrayOutputStream.toByteArray()), fileName);
                byteArrayOutputStream.close();
                //清空本次导出的数据列表
                expenseCountReportExportList.clear();
            }catch (Exception e){
                if(byteArrayOutputStream != null){
                    try {
                        byteArrayOutputStream.close();
                    } catch (IOException ex) {
                        logger.error(ex.getMessage(), ex);
                    }
                }
                logger.error("----导出支出统计报表异常--error={}", e.getMessage());
            }
        }

        try {
            // 注意关闭流的顺序，在上传oss之前必须关闭流否则下载解压的时候会报“文件末端错误”的问题
            outputStream.close();
            out.close();
        }catch (Exception e){
            logger.error("----导出支出统计报表异常关闭流异常--error={}", e.getMessage());
        }finally {

        }

        //上传文件到OSS当中
        InputStream byteArrayInputStream = new ByteArrayInputStream(outputStream.toByteArray());
        String zipFileName = "支出统计报表_" + System.currentTimeMillis() + ".zip";
        //上传文件通讯录
        exportInfoService.uploadExportFile(byteArrayInputStream, expenseCountReportExportResultDto.getMerId(), zipFileName, exportAmountVo, ExportInfoTypeEnum.EXPORT_INFO_EXPENSE_COUNT_REPORT.getId());

        //往reids插入本次下载，允许30分钟下载一次，避免频繁提交
        redisTemplate.opsForValue().set(String.format(CacheKey.EXPENSE_COUNT_REPORT_EXPORT, expenseCountReportExportResultDto.getMerId()),expenseCountReportExportResultDto.getMerId()+"",30, TimeUnit.MINUTES);

    }

}
